<template>
  <div>
    <a-button
      type="primary"
      @click="multipleDialog = true"
      v-if="useSelectButton"
      class="select-btn"
    >
      {{ buttonName }}
    </a-button>
    <a-table
      :columns="headColums.length > 0 ? headColums : columns"
      :bordered="showFormBorder"
      :pagination="false"
      :data-source="data"
      :scroll="{ x: 'max-content' }"
    >
      <template #summary>
        <a-table-summary-row v-if="columns.some((x) => x.componentProps?.subTotal)">
          <a-table-summary-cell v-for="(column, idx) in columns" :key="idx">
            <a-typography-text keyboard v-if="column.componentProps?.subTotal">
              {{ t('合计：') }} {{ sum(data.map((x) => x[column.dataIndex as string])) }}
            </a-typography-text>
          </a-table-summary-cell>
        </a-table-summary-row>
      </template>
      <template #bodyCell="{ column, record, index }">
        <template v-if="column.key !== 'action'">
          <template v-if="column.key === 'index'">
            {{ index + 1 }}
          </template>
          <FormItem
            :name="[mainKey, index, column.dataIndex]"
            :rules="rules(column, record)"
            :validateTrigger="['blur', 'change']"
            v-else
          >
            <!---如果是checked一类的组件-->
            <template v-if="checkedValueComponents.includes(column.componentType)">
              <component
                :is="componentMap.get(column.componentType)"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column.componentProps, record)"
                v-model:checked="record[column.dataIndex]"
              />
            </template>
            <!---如果是RangePicker组件-->
            <template
              v-else-if="
                column.componentType === 'RangePicker' || column.componentType === 'TimeRangePicker'
              "
            >
              <component
                :is="componentMap.get(column.componentType)"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column.componentProps, record)"
                v-model:startField="column.dataIndex.split(',')[0]"
                v-model:endField="column.dataIndex.split(',')[1]"
                @change="handleRangePickerChange(record, column.dataIndex)"
                v-model:value="record[column.dataIndex]"
                :mainKey="mainKey"
                :tableIndex="index"
              />
            </template>

            <!---如果是渲染函数组件-->
            <template v-else-if="column.componentType === 'Render'">
              <component
                :bordered="showComponentBorder"
                :is="
                  column.render({
                    model: record,
                    field: column.dataIndex,
                    rules: column.rules,

                    componentProps: getComponentsProps(column.componentProps, record),
                  })
                "
              />
              <!-- {{ column.render({ model: record, field: column.dataIndex }) }} -->
            </template>

            <template v-else-if="column.key !== 'index'">
              <component
                :is="componentMap.get(column.componentType)"
                :bordered="showComponentBorder"
                v-bind="getComponentsProps(column.componentProps, record)"
                :index="index"
                :mainKey="mainKey"
                v-model:value="record[column.dataIndex]"
              />
            </template>
          </FormItem>
        </template>
        <template v-if="column.key === 'action' && !disabled">
          <MinusCircleOutlined @click="remove(index)" style="padding-bottom: 20px" />
        </template>
      </template>
    </a-table>
    <a-button type="dashed" block @click="add" v-if="!disabled">
      <PlusOutlined />
      {{ t('新增') }}
    </a-button>
    <FormItemRest>
      <MultipleSelect
        ref="MultipleSelectRef"
        v-model:multipleDialog="multipleDialog"
        :params="{ itemId }"
        :datasourceType="preloadType"
        :dicOptions="dicOptions"
        :apiConfig="apiConfig"
        :isSubFormUse="true"
        @submit="renderSubFormList"
        popupType="preload"
      />
    </FormItemRest>
  </div>
</template>
<script lang="ts" setup>
  import { PlusOutlined, MinusCircleOutlined } from '@ant-design/icons-vue';
  import { Form } from 'ant-design-vue';
  import { inject, onMounted, ref, unref, watch, nextTick } from 'vue';
  import { SubFormColumn } from '../types';
  import { componentMap } from '../componentMap';
  import { DicDataComponents, checkedValueComponents, staticDataComponents } from '../helper';
  import { MultipleSelect } from '/@/components/MultiplePopup';
  import { dateUtil } from '/@/utils/dateUtil';
  import { isFunction, cloneDeep, isBoolean, sum } from 'lodash-es';
  import { deepMerge } from '/@/utils';
  import { apiConfigFunc } from '/@/utils/event/design';
  import { getDicDetailList } from '/@/api/system/dic';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { MutipleHeadInfo } from '/@/components/Designer';

  const { t } = useI18n();
  // 用于包裹弹窗的form组件 因为一个FormItem 只能收集一个表单组件  所以弹窗的form 必须排除
  // const FormItemRest = Form.ItemRest;
  const FormItem = Form.Item;
  const FormItemRest = Form.ItemRest;

  //const prereloadData = ref<Recordable[] | undefined>(undefined);
  const multipleDialog = ref<boolean>(false);
  const emit = defineEmits(['change', 'update:value']);

  const props = defineProps({
    /**
     * 如果是编辑状态 默认现实的值
     */
    value: { type: Array as PropType<Recordable[]>, default: () => [] },
    /**
     * 是否预加载
     */
    preload: {
      type: Boolean,
      default: false,
    },
    /**
     * 预加载 类型 开启 preload  为true 才有用
     * datasource || dataitem
     */
    preloadType: { type: String, default: null },

    /**
     * 需要绑定主表的字段  用于验证  必填
     */
    mainKey: { type: String, required: true },
    /**
     * 子表单配置
     */
    columns: {
      type: Array as PropType<SubFormColumn[]>,
      required: true,
    },
    /**
     * 是否禁用所有组件
     */
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * 预加载数据为api时使用
     */
    apiConfig: Object,
    /**
     * 预加载数据为数据字典时使用
     */
    itemId: String,
    dicOptions: Array,
    /**
     * 是否使用按钮选数据
     */
    useSelectButton: Boolean,
    /**
     * 选数据按钮名称
     */
    buttonName: String,
    //是否显示表格边框
    showFormBorder: Boolean,
    //是否显示组件边框
    showComponentBorder: Boolean,
    //是否展示序号
    showIndex: Boolean,
    //表头合并数据
    multipleHeads: { type: Array as PropType<MutipleHeadInfo[]> },
  });
  const data = ref<Recordable[]>([]);

  const headColums = ref<MutipleHeadInfo[]>([]); // 多表头
  const originHeads = ref<MutipleHeadInfo[]>([]); // 多表头源数据
  const columns = ref<SubFormColumn[]>(props.columns);

  // 注入表单数据
  const formModel = inject<any>('formModel', null);

  onMounted(() => {
    data.value = cloneDeep(props.value);

    if (props.showIndex && columns.value && columns.value[0].key !== 'index') {
      columns.value.unshift({
        title: '序号',
        key: 'index',
        align: 'center',
        width: 60,
      });
    }
    columns.value = filterColum(columns.value);
    nextTick(() => {
      //处理多表头
      if (props.multipleHeads && props.multipleHeads.length > 0) {
        originHeads.value = cloneDeep(props.multipleHeads);

        getColumns(columns.value);
        //过滤权限为不显示的组件
        filterHeads(headColums.value);
      }
    });
  });

  watch(
    () => props.columns,
    (val) => {
      columns.value = filterColum(val);
    },
  );

  watch(
    () => props.value,
    (v) => {
      data.value = v;
      const rangeComponents = props.columns.filter((column) =>
        column.componentType?.includes('Range'),
      );
      if (rangeComponents.length && formModel) {
        rangeComponents.forEach((item) => {
          data.value.forEach((x) => {
            if (x[(item.dataIndex as string)?.split(',')[0]]) {
              x[item.dataIndex as string] = [
                x[(item.dataIndex as string)?.split(',')[0]],
                x[(item.dataIndex as string)?.split(',')[1]],
              ];
            }
          });
        });
      }

      //要保证在预加载之后在emit  不然预加载数据不会绑定到表单数据中
      emit('change', unref(data));
      emit('update:value', unref(data));
    },
    { deep: true },
  );
  function getColumns(children) {
    let headsColumn: MutipleHeadInfo[] = [];
    let leafNode = 0;
    children.forEach((o) => {
      o.isleaf = false;
      let flag = false;
      for (let i = 0; i < originHeads.value.length; i++) {
        let k = originHeads.value[i];

        let idx = k.children.findIndex((j) => {
          return j == o.key || j.key == o.key;
        });
        if (idx >= 0) {
          o.isleaf = true;
          flag = true;
          leafNode += 1;
          k.children.splice(idx, 1, o);
          let obj = headsColumn.find((j) => {
            return j.key == k.key;
          });
          if (!obj) headsColumn.push(k);
          break;
        } else {
          flag = false;
        }
      }
      if (!flag) {
        let obj = headsColumn.find((j) => {
          return j.key == o.key;
        });
        if (!obj) headsColumn.push(o);
      }
    });
    if (leafNode > 0) {
      //继续循环
      getColumns(headsColumn);
    } else {
      headColums.value = headsColumn;
    }
  }
  function filterHeads(children) {
    children.forEach((k, i) => {
      if (typeof k == 'string') {
        children.splice(i, 1);
      } else if (k.children) {
        filterHeads(k.children);
      }
    });
  }

  const add = () => {
    //给各个组件赋默认值
    const pushObj: Recordable = {};
    props.columns.forEach((column, index) => {
      //判断是否为操作菜单  并且设置了默认值
      if (column.key === 'index' && index === 0) return;
      if (column.key !== 'action') {
        if (column.componentType === 'RangePicker' || column.componentType === 'TimeRangePicker') {
          handleSetRangeTimeValue(pushObj, column.dataIndex as string);
        } else if (
          (column.componentType &&
            staticDataComponents.includes(column.componentType) &&
            (column.componentProps as any)?.datasourceType === 'staticData') ||
          (column.componentType &&
            DicDataComponents.includes(column.componentType) &&
            (column.componentProps as any)?.datasourceType === 'dic')
        ) {
          let { defaultSelect } = column.componentProps as any;
          pushObj[column!.dataIndex as string] = defaultSelect;
        } else {
          pushObj[column!.dataIndex as string] = column.defaultValue;
        }
      }
    });
    data.value.push(pushObj);
    emit('change', unref(data));
    emit('update:value', unref(data));
  };

  const remove = (index) => {
    data.value.splice(index, 1);
    emit('change', unref(data));
    emit('update:value', unref(data));
  };

  const renderSubFormList = async (list) => {
    list?.forEach((x) => {
      const dataObj = {};
      columns.value?.map((item) => {
        if (!item?.dataIndex) return;
        dataObj[item.dataIndex as string] = item.componentProps?.prestrainField
          ? x[item.componentProps.prestrainField]
          : null;
      });

      data.value.push(dataObj);
    });
    emit('change', unref(data));
    emit('update:value', unref(data));
  };

  watch(
    () => props.preloadType,
    async (val) => {
      if (!!val && !props.useSelectButton) {
        let res;
        if (props.preloadType === 'api') {
          res = await apiConfigFunc(props.apiConfig, false, formModel);
        } else if (props.preloadType === 'dic') {
          res = await getDicDetailList({ itemId: props.itemId });
        }
        renderSubFormList(res);
      }
    },
    {
      immediate: true,
    },
  );
  /**
   * @author: tzx
   * @description: rangePicker组件的change事件
   */
  const handleRangePickerChange = (values: Recordable, field: string, format = 'YYYY-MM-DD') => {
    const startTimeKey = field.split(',')[0];
    const endTimeKey = field.split(',')[1];

    const [startTime, endTime]: string[] = values[field];
    values[startTimeKey] = dateUtil(startTime).format(format);
    values[endTimeKey] = dateUtil(endTime).format(format);

    return values;
  };

  /**
   * @author: tzx
   * @description: 设置RangeTime的值
   *
   */
  function handleSetRangeTimeValue(values: Recordable, field: string) {
    const startTimeKey = field.split(',')[0];
    const endTimeKey = field.split(',')[1];
    values[startTimeKey] = '';
    values[endTimeKey] = '';

    return values;
  }
  const rules = (column, record) => {
    if (column.key === 'index') return;
    const requiredRule = {
      required: getComponentsProps(column.componentProps, record)?.required || false,
      message: `${column.title}是必填项`,
    };
    const rulesList = cloneDeep(getComponentsProps(column.componentProps, record)?.rules);
    if (!rulesList) return [requiredRule];
    rulesList?.map((item) => (item.pattern = eval(item.pattern)));
    return [...rulesList, requiredRule];
  };

  const getComponentsProps = (componentProps, record) => {
    if (!componentProps) return;
    if (isFunction(componentProps)) {
      componentProps = componentProps({ updateSchema, formModel, record }) ?? {};
    }

    if (isBoolean(props.disabled)) {
      componentProps['disabled'] = componentProps['disabled'] || props.disabled;
    }
    return componentProps as Recordable;
  };

  const updateSchema = (column: SubFormColumn) => {
    let col: any = columns.value.find((x) => x.dataIndex == column.dataIndex);
    return col && col?.length ? deepMerge(col, column) : col;
  };
  function filterColum(column) {
    return column.filter((o) => {
      return (
        (isBoolean(o.show) && o.show) ||
        o.key == 'action' ||
        o.key == 'index' ||
        (!isBoolean(o.show) && !o.show)
      );
    });
  }
</script>
<style lang="less" scoped>
  :deep(.ant-form-item) {
    margin-bottom: 0;
  }

  :deep(.ant-table-cell) {
    padding: 8px 0;
  }

  :deep(.ant-table .ant-table-thead tr th) {
    padding: 11px;
  }

  :deep(.ant-input-number),
  :deep(.ant-input-affix-wrapper),
  :deep(.ant-input),
  :deep(.ant-select-selector),
  :deep(.ant-picker) {
    border: 0 !important;
    box-shadow: none !important;
  }

  :deep(.anticon) {
    padding-bottom: 0 !important;
  }

  :deep(.ant-table-cell-fix-right) {
    text-align: center;
    width: 60px;
  }

  :deep(.ant-radio-group),
  :deep(.ant-checkbox-group),
  :deep(.ant-rate),
  :deep(.ant-upload),
  :deep(.ant-form-item-explain-error) {
    padding: 0 11px;
  }

  :deep(.ant-switch),
  :deep(input[type='color']) {
    margin: 0 11px;
  }

  .select-btn {
    margin-bottom: 8px;
  }
</style>
